package main

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-vgo/robotgo"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

var (
	Info  *log.Logger
	Error *log.Logger
)

type configuration struct {
	Mode        string
	Port        string
	ShortcutKey string
	FilePath    string
	AllowOrigin string
}

func init() {
	file, err := os.OpenFile("sys.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		fmt.Println("日志文件打开失败")
	}
	Info = log.New(io.MultiWriter(file, os.Stderr), "INFO: ", log.Ldate|log.Ltime)
	Error = log.New(io.MultiWriter(file, os.Stderr), "ERROR: ", log.Ldate|log.Ltime)
	return
}

func main() {
	writeLog("开始读取配置文件...", 1)
	file, _ := os.Open("conf.json")
	defer func(file *os.File) {
		err := file.Close()
		if err != nil {
			writeLog("关闭配置文件失败", 0)
		}
	}(file)
	if file == nil {
		writeLog("读取配置文件失败", 0)
		return
	}
	writeLog("读取配置文件成功,开始解析...", 1)
	decoder := json.NewDecoder(file)
	conf := configuration{}
	err := decoder.Decode(&conf)
	if err != nil {
		writeLog("解析配置文件失败", 0)
		return
	}
	c, _ := json.Marshal(conf)
	writeLog("配置文件信息:"+string(c), 1)
	writeLog("服务已启动,监听端口:"+conf.Port+"...", 1)
	gin.SetMode(conf.Mode)
	r := gin.Default()
	r.Use(Cors(conf.AllowOrigin))
	r.GET("/", func(c *gin.Context) {
		c.String(http.StatusOK, "/***\n"+
			" *          .,:,,,                                        .::,,,::.\n"+
			" *        .::::,,;;,                                  .,;;:,,....:i:\n"+
			" *        :i,.::::,;i:.      ....,,:::::::::,....   .;i:,.  ......;i.\n"+
			" *        :;..:::;::::i;,,:::;:,,,,,,,,,,..,.,,:::iri:. .,:irsr:,.;i.\n"+
			" *        ;;..,::::;;;;ri,,,.                    ..,,:;s1s1ssrr;,.;r,\n"+
			" *        :;. ,::;ii;:,     . ...................     .;iirri;;;,,;i,\n"+
			" *        ,i. .;ri:.   ... ............................  .,,:;:,,,;i:\n"+
			" *        :s,.;r:... ....................................... .::;::s;\n"+
			" *        ,1r::. .............,,,.,,:,,........................,;iir;\n"+
			" *        ,s;...........     ..::.,;:,,.          ...............,;1s\n"+
			" *       :i,..,.              .,:,,::,.          .......... .......;1,\n"+
			" *      ir,....:rrssr;:,       ,,.,::.     .r5S9989398G95hr;. ....,.:s,\n"+
			" *     ;r,..,s9855513XHAG3i   .,,,,,,,.  ,S931,.,,.;s;s&BHHA8s.,..,..:r:\n"+
			" *    :r;..rGGh,  :SAG;;G@BS:.,,,,,,,,,.r83:      hHH1sXMBHHHM3..,,,,.ir.\n"+
			" *   ,si,.1GS,   sBMAAX&MBMB5,,,,,,:,,.:&8       3@HXHBMBHBBH#X,.,,,,,,rr\n"+
			" *   ;1:,,SH:   .A@&&B#&8H#BS,,,,,,,,,.,5XS,     3@MHABM&59M#As..,,,,:,is,\n"+
			" *  .rr,,,;9&1   hBHHBB&8AMGr,,,,,,,,,,,:h&&9s;   r9&BMHBHMB9:  . .,,,,;ri.\n"+
			" *  :1:....:5&XSi;r8BMBHHA9r:,......,,,,:ii19GG88899XHHH&GSr.      ...,:rs.\n"+
			" *  ;s.     .:sS8G8GG889hi.        ....,,:;:,.:irssrriii:,.        ...,,i1,\n"+
			" *  ;1,         ..,....,,isssi;,        .,,.                      ....,.i1,\n"+
			" *  ;h:               i9HHBMBBHAX9:         .                     ...,,,rs,\n"+
			" *  ,1i..            :A#MBBBBMHB##s                             ....,,,;si.\n"+
			" *  .r1,..        ,..;3BMBBBHBB#Bh.     ..                    ....,,,,,i1;\n"+
			" *   :h;..       .,..;,1XBMMMMBXs,.,, .. :: ,.               ....,,,,,,ss.\n"+
			" *    ih: ..    .;;;, ;;:s58A3i,..    ,. ,.:,,.             ...,,,,,:,s1,\n"+
			" *    .s1,....   .,;sh,  ,iSAXs;.    ,.  ,,.i85            ...,,,,,,:i1;\n"+
			" *     .rh: ...     rXG9XBBM#M#MHAX3hss13&&HHXr         .....,,,,,,,ih;\n"+
			" *      .s5: .....    i598X&&A&AAAAAA&XG851r:       ........,,,,:,,sh;\n"+
			" *      . ihr, ...  .         ..                    ........,,,,,;11:.\n"+
			" *         ,s1i. ...  ..,,,..,,,.,,.,,.,..       ........,,.,,.;s5i.\n"+
			" *          .:s1r,......................       ..............;shs,\n"+
			" *          . .:shr:.  ....                 ..............,ishs.\n"+
			" *              .,issr;,... ...........................,is1s;.\n"+
			" *                 .,is1si;:,....................,:;ir1sr;,\n"+
			" *                    ..:isssssrrii;::::::;;iirsssssr;:..\n"+
			" *                         .,::iiirsssssssssrri;;:.\n"+
			" */")
	})
	_, dirPath := os.Lstat(conf.FilePath)
	if dirPath != nil {
		os.Mkdir(conf.FilePath, 0777)
	}
	r.POST("/upload", func(c *gin.Context) {
		// Multipart form
		form, _ := c.MultipartForm()
		files := form.File["file"]
		//file= files[0]
		for _, file := range files {
			writeLog("处理文件:"+file.Filename, 1)
			_, fileName := path.Split(file.Filename)
			// 上传文件至指定目录
			err := c.SaveUploadedFile(file, conf.FilePath+"/"+fileName)
			if err != nil {
				fmt.Println(err)
			}
			absPath, _ := filepath.Abs(filepath.Dir(conf.FilePath))
			als := absPath + "/" + conf.FilePath + "/"
			filesPath := als + fileName
			mdConvertPdf(filesPath, conf)
			time.Sleep(5 * time.Second)
			killTypora()
			pdfFile := strings.Replace(strings.ToLower(fileName), ".md", ".pdf", -1)
			fmt.Println(als + pdfFile)
			buffer, count := readSourceFile(als + pdfFile)
			c.Writer.WriteHeader(http.StatusOK)
			t := time.Now().Unix()
			newFile := strconv.FormatInt(t, 10) + pdfFile
			c.Header("Content-Disposition", "attachment; filename="+newFile)
			c.Header("Content-Type", "application/octet-stream")
			c.Header("Accept-Length", fmt.Sprintf("%d", count))
			deleteSourceFile(filesPath, als+pdfFile)
			c.Writer.Write(buffer)
		}

	})
	errs := r.Run(":" + conf.Port)
	if errs != nil {
		return
	}
}

func mdConvertPdf(filePath string, conf configuration) {
	run := "start"
	writeLog("运行命令"+run+filePath, 1)
	cmd := exec.Command("cmd", "/C", run+" "+filePath)
	er := cmd.Start()
	if er != nil {
		writeLog(run+filePath+"命令执行失败", 0)
	}
	time.Sleep(3 * time.Second)
	err := robotgo.ActiveName("typora")
	if err != nil {
		writeLog("激活typora窗口失败", 0)
	}
	robotgo.KeySleep = 100
	time.Sleep(3 * time.Second)
	short := strings.Split(conf.ShortcutKey, "+")
	writeLog("开始按保存键"+conf.ShortcutKey, 1)
	errs := robotgo.KeyTap(short[0], short[1:])
	if errs != nil {
		writeLog("按保存快捷键失败", 0)
	}
	time.Sleep(1 * time.Second)
	robotgo.ActiveName("typora")
	time.Sleep(1 * time.Second)
	writeLog("开始敲回车键", 1)
	robotgo.KeyTap(robotgo.Enter)
}

func readSourceFile(filePath string) ([]byte, int) {
	file, _ := os.Open(filePath)
	defer file.Close()

	fileinfo, _ := file.Stat()

	filesize := fileinfo.Size()
	buffer := make([]byte, filesize)

	count, _ := file.Read(buffer)
	return buffer, count
}

func deleteSourceFile(mdFile, pdfFile string) {
	err := os.Remove(mdFile)
	if err != nil {
		writeLog("删除文件:"+mdFile+"失败", 0)
	}
	err1 := os.Remove(pdfFile)
	if err1 != nil {
		writeLog("删除文件:"+pdfFile+"失败", 0)
	}
}
func killTypora() {
	cmsStr := "TASKKILL /F /IM Typora.exe /T"
	cmd := exec.Command("cmd", "/C", cmsStr)
	err := cmd.Start()
	if err != nil {
		writeLog("关闭typora窗口失败", 0)
	}
}

func writeLog(content string, kind int) {
	switch kind {
	case 1:
		Info.Println(content)
		break
	case 0:
		Error.Println(content)
	}
}

// Cors 跨域中间件
func Cors(allowOrigin string) gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		origin := c.Request.Host
		if origin != "" {
			c.Header("Access-Control-Allow-Origin", allowOrigin) // 可将将 * 替换为指定的域名
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
			c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
			c.Header("Access-Control-Allow-Credentials", "true")
		}
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}
		c.Next()
	}
}
